﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Objects;

namespace HM.DataLayer
{
    public class DataAccess
    {
        #region Add

        public void AddTenant(Tenant tenant)
        {
            using (var context = new HMEntities())
            {
                context.AddToTenants(tenant);
                context.SaveChanges();
            }
        }

        public void AddPayment(Payment payment)
        {
            using (var context = new HMEntities())
            {
                context.AddToPayments(payment);
                context.SaveChanges();
            }
        }

        public void AddExpense(Expense expense)
        {
            using (var context = new HMEntities())
            {
                context.AddToExpenses(expense);
                context.SaveChanges();
            }
        }

        public void AddRegularExpense(RegularExpense regularExpense)
        {
            using (var context = new HMEntities())
            {
                context.AddToRegularExpenses(regularExpense);
                context.SaveChanges();
            }
        }

        #endregion

        #region Get

        public IEnumerable<Tenant> GetTenants()
        {
            using (var context = new HMEntities())
            {
                var result = context.Tenants.ToList();
                result.ForEach(t => context.Detach(t));
                return result.OrderBy(t => t.ApartmentNumber);
            }
        }

        public IEnumerable<Payment> GetPayments()
        {
            var context = new HMEntities();
            return context.Payments.ToList();
        }

        public IEnumerable<Payment> GetPaymentsByTenantsId(int tenantId)
        {
            using (var context = new HMEntities())
            {
                var result = context.Payments.Where(p => p.TenantId == tenantId).ToList();
                result.ForEach(p => context.Detach(p));
                return result;
            }
        }

        public IEnumerable<Payment> GetPaymentsByDateRange(DateTime? from, DateTime? to)
        {
            var context = new HMEntities();
            var result = context.Payments.Where(p => (p.PaymentDate >= from && p.PaymentDate <= to)).ToList();
            return result;
        }

        public IEnumerable<Expense> GetExpenses()
        {
            using (var context = new HMEntities())
            {
                return context.Expenses.ToList();
            }
        }

        public IEnumerable<Expense> GetExpensesByDateRange(DateTime? from, DateTime? to)
        {
            using (var context = new HMEntities())
            {
                var result = context.Expenses.Where(e => (e.PaymentDate >= from && e.PaymentDate <= to)).ToList();
                result.ForEach(e => context.Detach(e));
                return result;
            }
        }

        public IEnumerable<RegularExpense> GetRegularExpenses()
        {
            using (var context = new HMEntities())
            {
                return context.RegularExpenses.ToList();
            }
        }

        public Decimal? GetCash()
        {
            using (var context = new HMEntities())
            {
                Decimal? paymentsSum = 0.0m;
                Decimal? expensesSum = 0.0m;

                if (context.Payments.Count() > 0)
                    paymentsSum = context.Payments.Sum(p => p.Amount);

                if (context.Expenses.Count() > 0)
                    expensesSum = context.Expenses.Sum(e => e.Amount);

                return paymentsSum - expensesSum;
            }
        }

        public Decimal? GetCashForThisMonth()
        {
            using (var context = new HMEntities())
            {
                Decimal? paymentsSum = 0.0m;
                Decimal? expensesSum = 0.0m;

                if (context.Payments.Count() > 0)
                    paymentsSum = context.Payments.Where(p => ((DateTime)p.PaymentDate).Month == DateTime.Now.Month).Sum(p => p.Amount);

                if (context.Expenses.Count() > 0)
                    expensesSum = context.Expenses.Where(e => ((DateTime)e.PaymentDate).Month == DateTime.Now.Month).Sum(e => e.Amount);

                return paymentsSum - expensesSum;
            }
        }

        #endregion

        #region Save

        public void SaveTenants(IEnumerable<Tenant> tenants)
        {
            using (var context = new HMEntities())
            {
                foreach (var tenant in tenants)
                {
                    context.Attach(tenant);
                    context.ObjectStateManager.ChangeObjectState(tenant, EntityState.Modified);
                }
                context.SaveChanges();
            }
        }

        public void SaveRegularExpenses(IEnumerable<RegularExpense> regularExpenses)
        {
            using (var context = new HMEntities())
            {
                foreach (var regularExpense in regularExpenses)
                {
                    context.Attach(regularExpense);
                    context.ObjectStateManager.ChangeObjectState(regularExpense, EntityState.Modified);
                }
                context.SaveChanges();
            }
        }

        public void SaveExpenses(IEnumerable<Expense> expenses)
        {
            using (var context = new HMEntities())
            {
                foreach (var expense in expenses)
                {
                    context.Attach(expense);
                    context.ObjectStateManager.ChangeObjectState(expense, EntityState.Modified);
                }
                context.SaveChanges();
            }
        }

        public void SavePayments(IEnumerable<Payment> payments)
        {
            using (var context = new HMEntities())
            {
                foreach (var payment in payments)
                {
                    context.Attach(payment);
                    context.ObjectStateManager.ChangeObjectState(payment, EntityState.Modified);
                }
                context.SaveChanges();
            }
        }

        #endregion

        #region Remove

        public void RemoveTenant(Tenant tenant)
        {
            if (tenant != null)
            {
                using (var context = new HMEntities())
                {
                    context.Attach(tenant);
                    RemovePayments(tenant.Id); // Remove Tenant's payments before Tenant's removal
                    context.ObjectStateManager.ChangeObjectState(tenant, EntityState.Deleted);
                    context.SaveChanges();
                }
            }
        }

        public void RemoveRegularExpense(RegularExpense regularExpense)
        {
            using (var context = new HMEntities())
            {
                context.Attach(regularExpense);
                context.ObjectStateManager.ChangeObjectState(regularExpense, EntityState.Deleted);
                context.SaveChanges();
            }
        }

        public void RemoveExpense(Expense expense)
        {
            using (var context = new HMEntities())
            {
                context.Attach(expense);
                context.ObjectStateManager.ChangeObjectState(expense, EntityState.Deleted);
                context.SaveChanges();
            }
        }

        public void RemovePayment(Payment payment)
        {
            using (var context = new HMEntities())
            {
                context.Attach(payment);
                context.ObjectStateManager.ChangeObjectState(payment, EntityState.Deleted);
                context.SaveChanges();
            }
        }

        private void RemovePayments(int id)
        {
            IEnumerable<Payment> payments = GetPaymentsByTenantsId(id);

            using (var context = new HMEntities())
            {
                foreach (var payment in payments)
                {
                    context.Attach(payment);
                    context.ObjectStateManager.ChangeObjectState(payment, EntityState.Deleted);
                    context.SaveChanges();
                }
            }
        }

        #endregion
    }
}
